<!doctype html>

<html>

<head>
  <title>Templater</title>

  <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
  <link rel="stylesheet" type="text/css" href="../../style/popup/default/style.css" media="screen" />

  <style>
    #testEditArea
    {
      border: 2px solid #080;
      font-family: Consolas;
      line-height: 1.2;
    }
    #testEditArea1 *
    {
      margin: 2px !important;
      outline: 1px solid orange;
    }
    .line
    {
      white-space: pre;
      min-height: 1.2em;
    }
    #shadowEditBuffer
    {
      position: absolute;
      top: 50px;
      bot2tom: 0px;
      ri2ght: 0px;
      width: 100px;
      height: 100px;
    }
    .sel
    {
      background: gold;
    }
    .cursor
    {
      position: absolute;
      width: 0px;
      overflow: hidden;
      height: 1.2em;
      border-left: 1px solid black;
    }
    .cursor.hidden
    {
      border-color: transparent;
    }
    .Basis-Popup
    {
      margin: 8px 0 0 8px;
    }
  </style>
</head>

<body>
  <script type="text/javascript" src="../../basis-all.js"></script>

  <script>
    var popup = new basis.ui.popup.Popup({ dir: 'left bottom left top', content: 'test' });

    function putCursor(node, offset){
      if (node.nodeType == 3)
      {
        var insertPoint = node.nextSibling;
        var parentNode = node.parentNode;

        if (offset == 0)
          parentNode.insertBefore(cursor, node);
        else
          if (offset < node.nodeValue.length)
          {
            node.splitText(offset);
            parentNode.insertBefore(cursor, insertPoint ? insertPoint.previousSibling : parentNode.lastChild);
          }
          else
          {
            parentNode.insertBefore(cursor, insertPoint);
          }
      }
      else
      {
        node.insertBefore(cursor, node.childNodes[offset])
      }
      
    }

    var selWrapper;
    var editArea = basis.dom.createElement({
      description: '#testEditArea',

      /*mousedown: function(e){
        basis.dom.remove(cursor);
        cursorContainer = null;
      },*/
      mouseup: function(){
        var r = window.getSelection().getRangeAt(0);
        console.log(r)

        if (r.collapsed)
        {
          putCursor(r.startContainer, r.startOffset);

          cursorContainer = null;
          /*setTimeout(function(){
            popup.show(cursor);
          }, 0);*/
        }
        else
        {
          selWrapper = basis.dom.createElement('SPAN.sel');
          basis.dom.event.addHandler(selWrapper, 'mousemove', function(event){
            shadowEditBuffer.style.top = (event.pageY - 1) + 'px';
            shadowEditBuffer.style.left = (event.pageX - 1) + 'px';
          })
          r.surroundContents(selWrapper);
          shadowEditBuffer.value = r.toString();
        }

        shadowEditBuffer.select();
      }
    });

    function addContentAtCursor(editArea, content){
      if (!editArea.contains(cursor))
        return console.warn('cursor is not inside editArea');

      var lines = content.split(/\r\n?|\n\r?/);
      var prevTextNode = cursor.previousSibling;

      var text = lines.shift();
      if (prevTextNode)
        prevTextNode.nodeValue += text;
      else
      {
        if (text)
          cursor.parentNode.insertBefore(document.createTextNode(text), cursor);
      }

      if (lines.length)
      {
        var curLine = cursor.parentNode;
        var nextLine = curLine.nextSibling;
        var nextLineFirstTextNode

        var cur = cursor.nextSibling;
        var nextLineFragment = document.createDocumentFragment();

        while (cur)
        {
          nextLineFragment.appendChild(cur);
          cur = cur.nextSibling;
        }
        var first = nextLineFragment.firstChild;
        var trailText;
        if (text = lines.pop())
          trailText = nextLineFragment.insertBefore(document.createTextNode(text), first);
       
        nextLine = editArea.insertBefore(basis.dom.createElement('.line', nextLineFragment), nextLine);

        for (var i = 0, newLine; i < lines.length; i++)
        {
          newLine = editArea.insertBefore(basis.dom.createElement('.line'), nextLine);
          if (lines[i])
            newLine.appendChild(document.createTextNode(lines[i]));
        }

        nextLine.insertBefore(cursor, first || (trailText && trailText.nextSibling) || nextLine.firstChild);
      }

      popup.realign();
    }
    function addContent(editArea, pos, content){
      var lines = content.split(/\r\n?|\n\r?/);
      for (var i = 0; i < lines.length; i++)
      {
        var line = editArea.appendChild(basis.dom.createElement('.line'));
        if (lines[i])
          line.appendChild(document.createTextNode(lines[i]));
      }
    }
    addContent(editArea, 0, 'Text content\ntest test \n\n test test\nsdfsdfsdfsdf');

    function processBuffer(event){
      if (this.value)
      {
        addContentAtCursor(editArea, this.value);
        //cursor.parentNode.insertBefore(document.createTextNode(this.value), cursor);
        //this.value = '';
      }
    }

    var shadowEditBuffer = basis.dom.createElement({
      description: 'TEXTAREA#shadowEditBuffer',
      change: processBuffer,
      keyup: processBuffer,
      keypress: processBuffer,
      mousemove: function(event){
        this.style.top = (event.pageY - 8) + 'px';
        this.style.left = (event.pageX - 8) + 'px';
      },
      keydown: function(){
        processBuffer.call(this, event)

        var cur = cursor;
        var line = cursor.parentNode;
        if (!line) return;

        var nextLine = line.nextSibling;
        var prevLine = line.previousSibling;
        switch (basis.dom.event.key(event))
        {
          case basis.dom.event.KEY.UP:
            if (prevLine)
            {
              var pos = 0;
              basis.dom.axis(cursor, basis.dom.AXIS_PRESCENDING_SIBLING, function(node){
                if (node.nodeType == 3)
                  pos += node.nodeValue.length;
              });
              var c = prevLine.firstChild;
              var done = false;
              var index = 0;
              while (c && index <= pos)
              {
                if (c.nodeType == 3)
                {
                  if (index + c.nodeValue.length >= pos)
                  {
                    putCursor(c, pos - index);
                    done = true;
                    break;
                  }
                  else
                    index += c.nodeValue.length;
                }
                c = c.nextSibling;
              }
              if (!done)
                prevLine.appendChild(cursor);
            }
          break;
          case basis.dom.event.KEY.DOWN:
            if (nextLine)
            {
              var pos = 0;
              basis.dom.axis(cursor, basis.dom.AXIS_PRESCENDING_SIBLING, function(node){
                if (node.nodeType == 3)
                  pos += node.nodeValue.length;
              });
              var c = nextLine.firstChild;
              var done = false;
              var index = 0;
              while (c && index <= pos)
              {
                if (c.nodeType == 3)
                {
                  if (index + c.nodeValue.length >= pos)
                  {
                    putCursor(c, pos - index);
                    done = true;
                    break;
                  }
                  else
                    index += c.nodeValue.length;
                }
                c = c.nextSibling;
              }
              if (!done)
                nextLine.appendChild(cursor);
            }
          break;
          case basis.dom.event.KEY.RIGHT:
            if (cur = cursor.nextSibling)
              putCursor(cur, 1);
            else
            {
              if (nextLine)
                putCursor(nextLine, 0);
            }
          break;
          case basis.dom.event.KEY.LEFT:
            if (cur = cursor.previousSibling)
              putCursor(cur, cur.nodeValue.length - 1);
            else
            {
              if (prevLine)
                putCursor(prevLine, prevLine.childNodes.length);
            }
          break;
          case basis.dom.event.KEY.HOME:
            putCursor(line, 0);
          break;
          case basis.dom.event.KEY.END:
            putCursor(line, line.childNodes.length);
          break;
          case basis.dom.event.KEY.DELETE:
            if (cur = cursor.nextSibling)
            {
              if (cur.nodeValue.length == 1)
                basis.dom.remove(cur);
              else
                cur.nodeValue = cur.nodeValue.substr(1);
            }
            else
            {
              if (nextLine)
              {
                basis.dom.remove(nextLine);
                basis.dom.insert(line, Array.from(nextLine.childNodes));
              }
            }
          break;
        }
        popup.realign()
      },
      focus: function(){
        //console.log('focus');
        if (cursorContainer)
          cursorContainer.insertBefore(cursor, cursorInsertPoint);
      },
      blur: function(){
        //console.log('blur');
        if (cursor.parentNode && cursor.parentNode.nodeType != 11)
        {
          cursorContainer = cursor.parentNode;
          cursorInsertPoint = cursor.nextSibling;
          basis.dom.remove(cursor);
        }
      }
    });

    var cursorContainer;
    var cursorInsertPoint;
    var cursor = basis.dom.createElement('SPAN.cursor');
    setInterval(function(){
      basis.cssom.classList(cursor).toggle('hidden');
    }, 500);

    basis.dom.insert(document.body, shadowEditBuffer);
    basis.dom.insert(document.body, editArea);


    function onmousedown(event){
      editArea.dispatchEvent(event);

      if (!basis.dom.event.mouseButton(event, basis.dom.event.MOUSE_LEFT))
      {
        this.value='test data';
        this.select();
      }
    }
  </script>
  <!--<textarea id="xx" onmousedown="onmousedown" oncontextmenu="this.value='xxx';this.select()" style="position: absolute;top: 50px;">
  </textarea>
  <button onclick="document.getElementById('xx').value = ''">reset</button>-->
</body>

</html>
